package cn.gzmli.dtt.common.utils;

import cn.gzmli.dtt.common.config.cache.Config;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.ObjectMapper;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 20161110请求参数验证类
 * @author wonderful
 * @version 1.0
 *
 */
public class Validator {


	private static String INT_REX="^[0-9]+\\d*$";
	private static String FLOAT_REX="^[0-9]+\\.{1}\\d+$";
	private static String DATATIME_REX="(\\d{1,4}[-|\\/|年|\\.]\\d{1,2}[-|\\/|月|\\.]\\d{1,2}([日|号])?(\\s)*(\\d{1,2}([点|时])?((:)?\\d{1,2}(分)?((:)?\\d{1,2}(秒)?)?)?)?(\\s)*(PM|AM)?)";
	private static String PRIC_REX="^[0-9]+\\.{1}[0-9]+$";

	//接口请求参数验证配置数据缓存
	private static Map<String,Map<String,Object>> VALIDATOR_CONF;
	/**
	 * 获取参数验证配置对象
	 * @return
	 * @throws Exception
	 */
	public static Map<String,Map<String,Object>> loadValidatorConf()throws IOException {



		File file=new File(Config.VALIDATOR_CONF_PATH);
		FileInputStream fis=new FileInputStream(file);
		byte[] buffer=new byte[fis.available()];
		fis.read(buffer);
		String validatorJson=new String(buffer,"UTF-8");
		validatorJson=validatorJson.replaceAll("\\/\\/[^\\n]*","");
		ObjectMapper objectMapper = new ObjectMapper();
		objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
		VALIDATOR_CONF = objectMapper.readValue(
				validatorJson,Map.class);

		return VALIDATOR_CONF;
	}

	public static Map<String,Map<String,Object>> loadValidatorConf(String filePath)throws IOException {

		File file=new File(filePath);
		FileInputStream fis=new FileInputStream(file);
		byte[] buffer=new byte[fis.available()];
		fis.read(buffer);
		String validatorJson=new String(buffer,"UTF-8");
		validatorJson=validatorJson.replaceAll("\\/\\/[^\\n]*","");
		ObjectMapper objectMapper = new ObjectMapper();
		objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

		return objectMapper.readValue(validatorJson,Map.class);
	}

	//前置条件参数触发
	public static boolean isTrigger(Map<String,String> reqParams, Map<String, Object> valParam){
		boolean isTrigger=false;

		if(valParam.get("triggerConds")!=null){
			List<Map<String,Object>> triggerConds=(List<Map<String,Object>>)valParam.get("triggerConds");
			for(Map<String,Object> triggerCond:triggerConds){
				String paramVal=reqParams.get(triggerCond.get("paramName").toString());
				if(paramVal!=null&&paramVal.equals(triggerCond.get("paramVal").toString()))
				{
					isTrigger=true;
					break;
				}
			}
		}else{
			isTrigger=true;
		}

		return isTrigger;
	}

	//参数验证
	public static Map<String,Object> validate(String urlPath, Map<String,String> reqParams)throws NumberFormatException, IOException {

		int slashIndex=0;
		String spaceName="undefined";
		//截取地址的控制层命名空间名称
		for(int i=urlPath.length()-1;i>=0;i--){
			char c=urlPath.charAt(i);
			//每匹配一次斜杠就记录一次斜杠索引
			if(c=='/'){
				slashIndex++;
			}

			//当斜杠索引等于2时控制层命名空间地址检索完成，从当前字符索引截取以获得控制层命名空间
			if(slashIndex==2){
				if(urlPath.lastIndexOf("/")>i){
					spaceName=urlPath.substring(i+1,urlPath.lastIndexOf("/"))+".conf";
				}else if(urlPath.lastIndexOf("/")==i){
					spaceName=urlPath.substring(i+1)+".conf";
				}
				break;
			}
		}

		Map<String,Object> result=new HashMap<String,Object>();
		Map<String,Object> validatorParam=new HashMap<String,Object>();
		//获取独立的请求参数验证配置文件
		File file=new File(Config.VALIDATOR_CONF_BASEPATH+spaceName);
		//判断文件是否存在，如果存在在调用独立的请求参数验证配置文件，如果不存在则调用统一的请参数验证配置缓存
		if(file.exists()){
			validatorParam=Validator.loadValidatorConf(Config.VALIDATOR_CONF_BASEPATH+spaceName).get(urlPath);
		}
		else{
			validatorParam=VALIDATOR_CONF.get(urlPath);
		}

		if(validatorParam!=null){

			List<Map<String,Object>> specConds=(List<Map<String,Object>>)validatorParam.get("specConds");

			boolean isMeet=false;

			if(specConds!=null){

				for(Map<String,Object> specCond:specConds){

					String paramName = specCond.get("paramName").toString();
					String paramVal = specCond.get("paramVal").toString();
					String reqParamVal=reqParams.get(paramName);

					if(reqParamVal!=null&&reqParamVal.equals(paramVal)){

						isMeet=true;
						break;
					}
				}

			}else{
				isMeet=true;
			}

			//如果请求地址以及条件参数满足则进入验证环节
			if(isMeet){
				List<Map<String,Object>> valParams=(List<Map<String,Object>>)validatorParam.get("valParams");
				boolean isShowMsg=(boolean)validatorParam.get("isShowMsg");
				for(Map<String, Object> valParam:valParams){
					String paramName=valParam.get("paramName").toString();
					//判断是否触发该验证
					if(!isTrigger(reqParams,valParam)){
						continue;
					}

					List<Map<String,Object>> auTypes=(List<Map<String,Object>>)valParam.get("auTypes");

					for(Map<String,Object> auType:auTypes){


						String typeName = auType.get("typeName").toString();
						String errMsg = auType.get("errMsg").toString();
						String reqParamVal=reqParams.get(paramName);


						if(typeName!=null&&errMsg!=null){

							if((typeName.equals("isNotNull")&&reqParamVal==null)
									||(typeName.equals("isNotNull")&&reqParamVal!=null&&reqParamVal.equals(""))){

								result.put("status","2");//参数错误
								if(isShowMsg&&errMsg!=null){//如果显示错误消息为真
									result.put("msg",errMsg);
								}
								else{
									result.put("msg","参数输入错误！");
								}
								break;
							}
							else if(typeName.equals("isNotNull")
									&&reqParamVal!=null
									&&reqParamVal.equalsIgnoreCase("null")){

								result.put("status","2");//参数错误
								if(isShowMsg&&errMsg!=null){//如果显示错误消息为真
									result.put("msg",errMsg);
								}
								else{
									result.put("msg","参数输入错误！");
								}
								break;
							}else{
								if(reqParamVal!=null&&reqParamVal.trim().length()>0){
									if(typeName.equals("isFloat")
											&&reqParamVal!=null
											&&!reqParamVal.matches(FLOAT_REX)){

										result.put("status","2");//参数错误
										if(isShowMsg&&errMsg!=null){//如果显示错误消息为真
											result.put("msg",errMsg);
										}
										else{
											result.put("msg","参数输入错误！");
										}

										break;
									}
									else if(typeName.equals("isInt")
											&&reqParamVal!=null
											&&!reqParamVal.matches(INT_REX)){

										result.put("status","2");//参数错误
										if(isShowMsg&&errMsg!=null){//如果显示错误消息为真
											result.put("msg",errMsg);
										}
										else{
											result.put("msg","参数输入错误！");
										}

										break;
									}
									else if(typeName.equals("isDateTime")
											&&reqParamVal!=null
											&&!reqParamVal.matches(DATATIME_REX)){

										result.put("status","2");//参数错误
										if(isShowMsg&&errMsg!=null){//如果显示错误消息为真
											result.put("msg",errMsg);
										}
										else{
											result.put("msg","参数输入错误！");
										}

										break;
									}
									else if(typeName.equals("isIn")
											&&reqParamVal!=null
											&&auType.get("inVals")!=null
											&&!BaseUtil.isInclude(auType.get("inVals").toString(),reqParamVal,",")){


										result.put("status","2");//参数错误
										if(isShowMsg&&errMsg!=null){//如果显示错误消息为真
											result.put("msg",errMsg);
										}
										else{
											result.put("msg","参数输入错误！");
										}

										break;
									}
									else if(typeName.equals("isPric")
											&&reqParamVal!=null
											&&!reqParamVal.matches(PRIC_REX)){


										result.put("status","2");//参数错误
										if(isShowMsg&&errMsg!=null){//如果显示错误消息为真
											result.put("msg",errMsg);
										}
										else{
											result.put("msg","参数输入错误！");
										}

										break;
									}
									//先满足整数条件，再比较最大值
									else if((typeName.equals("isMaxLen")
											&&reqParamVal!=null
											&&!reqParamVal.matches(INT_REX))
											||(typeName.equals("isMaxLen")
											&&reqParamVal!=null
											&&reqParamVal.matches(INT_REX)
											&&!(Integer.parseInt(reqParamVal)
											<=Integer.parseInt(auType.get("maxLenVal").toString()))
									)
											){

										result.put("status","2");//参数错误
										if(isShowMsg&&errMsg!=null){//如果显示错误消息为真
											result.put("msg",errMsg);
										}
										else{
											result.put("msg","参数输入错误！");
										}

										break;
									}
								}
							}

						}

					}


					//如果该参数验证通过并且是自动加载参数项，则自动把参数装载到查询类接口的查询条件
					if(result.get("status")==null
							&&valParam.get("isAPQC")!=null
							&&valParam.get("condKey")!=null
							&&valParam.get("condVal")!=null
							&&reqParams.get(paramName)!=null&&reqParams.get(paramName).toString().trim().length()>0
							){

						boolean isAPQC=(boolean)valParam.get("isAPQC");
						String condKey=valParam.get("condKey").toString();

						String condVal=valParam.get("condVal").toString();;
						//如果是in 筛选条件，则对参数进行in条件格式化
						if(valParam.get("isInCond")!=null&&Boolean.valueOf(valParam.get("isInCond").toString())){
							condVal=String.format(condVal,BaseUtil.toInCondNotSprit(reqParams.get(paramName).toString()));
						}else{
							condVal=String.format(condVal,reqParams.get(paramName).toString());
						}


						if(result.get("queryCond")!=null){
							Map<String,String> queryCond=(Map<String,String>)result.get("queryCond");
							queryCond.put(condKey,condVal);
						}else{
							Map<String,String> queryCond=new HashMap<String,String>();
							queryCond.put(condKey,condVal);
							result.put("queryCond",queryCond);
						}

					}

				}

			}

		}


		//如果没验证状态值，则证明验证通过。
		if(result.get("status")==null){
			result.put("status","1");
			result.put("msg","验证通过");
		}
		return result;
	}

}
